<template>
  <div class="container ml-3">
    <el-form  label-position="left" ref="elForm" :model="form"  size="medium" label-width="100px">

      <el-form-item label="配置模式" label-width="120px">
        <select v-model.number="mode" placeholder="" @change="changeMode">
          <option label="普通模式" :value="0"></option>
          <option label="专家模式" :value="1"></option>
        </select>
      </el-form-item>

      <div class="flex my-4 gap-8">
          <div class="w-[423px] h-[345px] relative shrink-0" id="c"
               @dblclick="handleDoubleClick">

              <videoPlayer
                class="object-fill  w-full h-[345px] " :class="full ? '!h-full !object-contain': ''"></videoPlayer>
              <canvas v-show="mode == 1"
                id="canvas"
                ref="canvas"
                width="423"
                height="345"
                @mousedown="handleMouseDown"
                @mousemove="handleMouseMove"
                @mouseup="handleMouseUp"
                @mouseleave="handleMouseLeave" class="absolute top-0 bottom-0 left-0 right-0 w-[423px] h-[345px] "></canvas>
          </div>

          <div v-show="mode == 0" class="min-w-[350px]">
            <el-form-item label="发射率" label-width="120px">
              <select v-model="form.emissivity" placeholder="" @change="handleemissivity">
                <option label="粗糙" :value="0.95"></option>
                <option label="较粗糙" :value="0.8"></option>
                <option label="较光滑" :value="0.6"></option>
                <option label="光滑" :value="0.3"></option>
                <option label="自定义" :value="0"></option>
              </select>
            </el-form-item>
            <el-form-item label="发射率值" label-width="120px">
              <input type="number" :min="0.01" :max="1" @change="handleemissivityValue"
                     :disabled="form.emissivity != 0" :step="0.1" v-model="form.emissivityValue" class="w-[202px]">
            </el-form-item>
            <el-form-item label="距离" label-width="120px">
              <input   type="text"
                       maxlength="4"
                       v-model="form.distance"
                       @input="handleFloatInput" class="w-[202px]">m
            </el-form-item>
            <el-form-item label="反射温度" label-width="120px">
              <input TYPE="number"  v-model="form.reflectTemp" class="w-[202px]">℃
            </el-form-item>
            <el-form-item label="透射率" label-width="120px">
              <input type="number" min="0.01" max="1" :step="0.1"  v-model="form.transmission" class="w-[202px]">
            </el-form-item>
            <el-form-item label="环境温度" label-width="120px">
              <input TYPE="number"   v-model="form.ambientTempManu" class="w-[202px]">℃
            </el-form-item>
            <el-form-item label="相对湿度" label-width="120px">
              <input  TYPE="number" :step="0.1"  v-model="form.humidity" class="w-[202px]">
            </el-form-item>
  <!--          <el-form-item label="预警温度" label-width="120px">-->
  <!--            <input  TYPE="number"  v-model="form.alert" class="w-[202px]">℃-->
  <!--          </el-form-item>-->
  <!--          <el-form-item label="过滤时间" label-width="120px">-->
  <!--            <input  TYPE="number"  v-model="form.alertFilterTime" class="w-[202px]">秒-->
  <!--          </el-form-item>-->
  <!--          <el-form-item label="报警温度" label-width="120px">-->
  <!--            <input TYPE="number"   v-model="form.alarm" class="w-[202px]">℃-->
  <!--          </el-form-item>-->
  <!--          <el-form-item label="过滤时间" label-width="120px">-->
  <!--            <input TYPE="number"   v-model="form.alarmFilterTime" class="w-[202px]">秒-->
  <!--          </el-form-item>-->
  <!--          <el-form-item label="容差温度" label-width="120px">-->
  <!--            <input  TYPE="number"  v-model="form.threshold" class="w-[202px]">℃-->
  <!--          </el-form-item>-->
        </div>


          <div v-show="mode == 1" class="shrink-0">
          <div class="flex gap-4">
            <div class="grid grid-cols-3 grid-rows-3 gap-1">
              <span class="a a1 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('UpLeft')" title="左上"
                    @mouseup="stopMove"></span>
              <span class="a a2 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('Up')" title="上"
                    @mouseup="stopMove"></span>
              <span class="a a3 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('UpRight')" title="右上"
                    @mouseup="stopMove"></span>

              <!-- Row 2 -->
              <span class="a a4 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('Left')" title="左"
                    @mouseup="stopMove"></span>
              <span title="自动" class="a a5 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"></span> <!-- No action -->
              <span class="a a6 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('Right')" title="右"
                    @mouseup="stopMove"></span>

              <!-- Row 3 -->
              <span class="a a7 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('DownLeft')" title="左下"
                    @mouseup="stopMove"></span>
              <span class="a a8 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('Down')" title="下"
                    @mouseup="stopMove"></span>
              <span class="a a9 p-2 border-[1px] border-gray-300 rounded-sm size-[32px]"
                    @mousedown="startMove('DownRight')" title="右下"
                    @mouseup="stopMove"></span></div>
            <div class="grid grid-cols-2 grid-rows-3 gap-1">
          <span   @mousedown="startZoom('In')"
                  @mouseup="startZoom('Stop')" title="调焦 -"
                  class="a b b1 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
              <span  @mousedown="startZoom('Out')" title="调焦 +"
                     @mouseup="startZoom('Stop')" class="a b2 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
              <span   @mousedown="startFocus('Near')" title="聚焦 -"
                      @mouseup="startFocus('Stop')" class="a b3 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
              <span   @mousedown="startFocus('Far')" title="聚焦 +"
                      @mouseup="startFocus('Stop')" class="a b4 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
              <span title="光圈 -" class="a b5 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
              <span title="光圈 +" class="a b6 p-2 border-[1px] border-gray-300 rounded-sm size-[37px]"></span>
            </div>
          </div>
          <div class="flex items-center">
            <el-slider
              v-model="speed" class="mx-2 w-4/5" :min="1" :max="9"
              :step="1">
            </el-slider>
            <span>{{  speed }}</span>
          </div>

          <div class="mt-1 flex flex-col gap-1 max-h-[200px] h-[200px]">

            <div class="flex flex-col border-[1px] border-gray-300 rounded-sm
overflow-y-auto flex-1 min-h-0 z-10">
              <div v-for="(item, i) in presets" :key="item.id"
                   class="group relative flex py-2 text-[12px] shrink-0 gap-2 items-center"
                   :class="{
         'bg-[#eeeeee]': selected === i && item.status,
         'text-gray-400': !item.status,
         'hover:bg-gray-100': item.status,
         'cursor-pointer': item.status
       }">
                <!--              <span class="pl-2 w-8 text-center shrink-0">{{ item.id }}</span>-->
                <div class="flex-1 ml-2 grow ms overflow-ellipsis">
                  <!-- 显示模式 -->
                  <span v-if="editingIndex !== i" @dblclick="item.status && startEdit(i, item)">
        {{ item.name }}
      </span>
                  <!-- 编辑模式 -->
                  <input
                    v-else
                    :maxlength="16"
                    type="text"
                    v-model="item.name"
                    class="w-full !text-[10px] max-w-[80px] py-0 border border-gray-400 rounded focus:outline-none focus:border-blue-500"
                    ref="editInput"
                    @blur="finishEdit(item)"
                    @keyup.enter="finishEdit(item)"
                  />
                </div>

                <!-- 悬浮时显示的操作按钮 -->
                <div class="absolute right-2 top-1/2 -translate-y-1/2 invisible group-hover:visible flex gap-1 p-1 rounded">
                  <!-- 未设置状态下的按钮 -->
                  <div v-if="!item.status" class="flex">
                    <el-button
                      v-if="capabilities.ptzSupport"
                      title="设置"
                      class="!p-0 !size-[24px] el-icon-setting !border-none !bg-transparent !mx-0"
                      @click.stop="setOrUpdatePreset(item)"
                    ></el-button>
                  </div>

                  <!-- 已设置状态下的按钮 -->
                  <div v-else class="flex">
                    <el-button
                      title="调用"
                      class="!p-0 !size-[24px] el-icon-video-play !border-0 !bg-transparent !mx-0"
                      @click.stop="handleClick(item, i)"
                    ></el-button>
                    <el-button
                      title="设置"
                      class="!p-0 !size-[24px] el-icon-setting !border-none !bg-transparent !mx-0"
                      @click.stop="setOrUpdatePreset(item)"
                    ></el-button>
                    <el-button
                      title="删除"
                      class="!p-0 !size-[24px] el-icon-delete !border-none !bg-transparent !mx-0"
                      @click.stop="removePreset(item, i)"
                    ></el-button>
                  </div>
                </div>
              </div>
            </div>
        </div>
        </div>

      </div>

      <div v-show="mode == 1">
        <el-table class="t mt-4 !max-w-[1060px] !min-w-[1060px]" border highlight-current-row
          :data="tableData" height="300"
          :cell-style="{ textAlign: 'center' }"
          :header-cell-style="{ 'text-align': 'center' }"
                  @current-change="handleCurrentRowChange"
          style="width: 70%">
          <el-table-column
            label="启用"
            width="60" class="flex items-center">
            <template slot-scope="scope">
              <el-checkbox  v-model="scope.row.validFlag" :true-label="1"
              :false-label="0"></el-checkbox>

            </template>
          </el-table-column>
          <el-table-column
            label="ID"
            width="60">
            <template slot-scope="scope">
              <span>{{ scope.row.id }}</span>
            </template>
          </el-table-column>
          <el-table-column
            label="名称"
            width="130">
            <template slot-scope="scope">
              <input :maxlength="32" v-model="scope.row.name" placeholder="">
            </template>
          </el-table-column>
          <el-table-column
            label="类型"
            width="130">
            <template slot-scope="scope">
              <select
                      :value="scope.row.type"
                      @change="handleTypeChange($event, scope.row)">
                <option label="点" value="point"></option>
                <option label="线" value="line"></option>
                <option label="框" value="rect"></option>
              </select>
            </template>
          </el-table-column>
          <el-table-column
            label="发射率"
            width="220">
            <template slot-scope="scope">
              <div class="flex">
                <select v-model="scope.row.emissivity" placeholder="" @change="handleemissivity2(scope.row)">
                  <option label="粗糙" :value="0.95"></option>
                  <option label="较粗糙" :value="0.8"></option>
                  <option label="较光滑" :value="0.6"></option>
                  <option label="光滑" :value="0.3"></option>
                  <option label="自定义" :value="0"></option>
                </select>
                <input v-model="scope.row.emissivityValue" @change="handleemissivityValue2(scope.row)"
                       :min="0.01" :max="1" :step="0.1" :disabled="scope.row.emissivity != 0" placeholder="" class="!w-[60px]">

              </div>

            </template>
          </el-table-column>

          <el-table-column
            label="距离(m)"
            width="130">
            <template slot-scope="scope">
              <input v-model="scope.row.distance" placeholder="">
            </template>
          </el-table-column>
          <el-table-column
            label="反射温度(℃)"
            width="140">
            <template slot-scope="scope">

              <div class="flex">
<!--                <el-checkbox  v-model="scope.row.reflectTempEnabled"></el-checkbox>-->
                <input v-model="scope.row.reflectTemp" placeholder="">
              </div>
            </template>
          </el-table-column>
<!--          <el-table-column-->
<!--            label="报警规则"-->
<!--            width="80">-->
<!--            <template slot-scope="scope">-->
<!--                <el-checkbox  v-model="scope.row.rule"></el-checkbox>-->
<!--            </template>-->
<!--          </el-table-column>-->
          <el-table-column
            label="报警规则"
            width="80">
            <template slot-scope="scope">
<div class="relative size-[30px] w-full flex items-center justify-center"
     @mouseenter="hoverRule(scope.row, $event)">
            <i class="e absolute top-[0px]"
               @click="handleSettingClick($event, scope.row)"></i>
<!--              <div v-if="tooltipVisible" class="absolute z-10 top-10 left-0 w-full h-full bg-white border border-gray-300 rounded-md">-->
<!--                <div>-->
<!--                  预警温度 {{ tooltip.alertTemp }} ℃-->
<!--                </div>-->
<!--               </div>-->
            </div>
            </template>
          </el-table-column>

          <el-table-column
            label="测温输出"
            width="80">
            <template slot-scope="scope">
              <div class="relative size-[30px] w-full flex items-center justify-center">
                <i class="e absolute top-[0px]" @click="handleTempOutputClick($event, scope.row)"></i>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </div>

      <el-dialog title="报警规则" @close="settingClose" :visible.sync="dialogVisible" width="350px">
        <el-form :model="form1" label-width="80px" ref="elForm1">
          <el-form-item
            label="规则启用"
            width="80">
                <el-checkbox v-model="form1.enable" :true-label="1" :false-label="0"
                ></el-checkbox>
          </el-form-item>
          <el-form-item label="报警规则" prop="ruleType">
            <select v-model="form1.ruleType" placeholder="" class="!w-[182px]">
              <option value="" disabled selected>请选择规则</option>
              <option label="最高温高于" value="maxGreater"></option>
              <option label="最高温低于" value="maxLesser"></option>
              <option label="最低温高于" value="minGreater"></option>
              <option label="最低温低于" value="minLesser"></option>
              <option label="平均温高于" value="avgGreater"></option>
              <option label="平均温低于" value="avgLesser"></option>
            </select>
          </el-form-item>
          <el-form-item label="报警温度" prop="alarmTemp">
            <input type="number" v-model.number="form1.alarmTemp" placeholder="">℃
          </el-form-item>
          <el-form-item label="过滤时间" prop="alarmFilterTime">
            <input type="number" v-model.number="form1.alarmFilterTime" placeholder="">秒
          </el-form-item>
          <el-form-item label="预警温度" prop="alertTemp">
            <input type="number" v-model.number="form1.alertTemp" placeholder="">℃
          </el-form-item>
          <el-form-item label="过滤时间" prop="alertFilterTime">
            <input type="number" v-model.number="form1.alertFilterTime" placeholder="">秒
          </el-form-item>
          <el-form-item label="容差温度" prop="threshold">
            <input type="number" v-model.number="form1.threshold" placeholder="">℃
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button @click="dialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="handleDialogSave">保 存</el-button>
          </span>
      </el-dialog>


      <!-- 测温输出配置对话框 -->
      <el-dialog title="测温输出配置" :visible.sync="tempOutputDialogVisible" width="350px" @close="tempOutputDialogClose">
        <el-form :model="tempOutputForm" label-width="100px" ref="tempOutputForm">
          <el-form-item label="启用">
            <el-checkbox v-model="tempOutputForm.enable" :true-label="1" :false-label="0"></el-checkbox>
          </el-form-item>
          <el-form-item label="输出类型">
            <select v-model.number="tempOutputForm.outputType" class="!w-[182px]">
              <option label="LED display" :value="1"></option>
            </select>
          </el-form-item>
          <el-form-item label="输出地址">
            <input type="number" v-model.number="tempOutputForm.outputAddr" placeholder="1~255" class="!w-[182px]">
          </el-form-item>
          <el-form-item label="测温类型">
            <select v-model="tempOutputForm.tempType" :disabled="tempOutputForm.type == 'point'" class="!w-[182px]">
              <option label="最高温" value="maxTemp"></option>
              <option label="最低温" value="minTemp"></option>
              <option label="平均温" value="avgTemp"></option>
            </select>
          </el-form-item>
          <el-form-item label="输出间隔(s)">
            <input type="number" v-model.number="tempOutputForm.outputInterval" class="!w-[182px]">
          </el-form-item>
          <el-form-item label="计算方式">
            <select v-model.number="tempOutputForm.calcType" class="!w-[182px]">
              <option label="中值" :value="1"></option>
              <option label="均值" :value="2"></option>
            </select>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button @click="tempOutputDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="handleTempOutputSave">保 存</el-button>
        </span>
      </el-dialog>

      <el-button class="!mt-8" @click="save"
                 type="primary" style="margin-left: 0px; width: 120px">保存</el-button>
    </el-form>
  </div>
</template>

<script>
import {controlfocus, controlstop, direct, getbadpixelMode, getMeasurerect, getvideoparam, zoom} from "@/api/api";
import {
  getMeasureLine, getMeasureParam,
  getMeasurePoint, getQueryPreset, getThermalAlarmConfig, measureClear,
  postMeasureLine,
  postMeasureParam,
  getTempOutputConfig,
  postTempOutputConfig,
  postMeasurePoint,
  postMeasureRect, postPreset, postThermalAlarmConfig, getMeasureMode, postMeasureMode, getCapabilities
} from "@/api/api2";

import videoPlayer from "@/views/mini/videoplayer.vue"
import screenfull from "screenfull";
const SHAPE_POINT = 'point';
const SHAPE_LINE = 'line';
const SHAPE_RECT = 'rect';

const POINT_SIZE = 15; // Half-size of the crosshair
const HANDLE_SIZE = 8; // Size of resize handles
const LINE_DETECT_THRESHOLD = 5; // Pixels tolerance for clicking near a line

export default {
  name: 'TableCanvasLink',
  components: {
    videoPlayer
  },
  data() {
    return {
      capabilities: {
        "ptzSupport": 0,
        "focusSupport": 1,
        "zoomSupport": 0,
        "irisSupport": 0,
        "lightSupport": 0,
        "wiperSupport": 0,
        measureTempSupport: 1 ,
      },
      tempOutputDialogVisible: false,
      tempOutputForm: {},
      radTable: [
        /*
        * <option label="粗糙" :value="0.95"></option>
                  <option label="较粗糙" :value="0.8"></option>
                  <option label="较光滑" :value="0.6"></option>
                  <option label="光滑" :value="0.3"></option>
                  <option label="自定义" :value="0"></option>
                  * */
        {
          label: "粗糙",
          value: 0.95
        },
        {
          label: "较粗糙",
          value: 0.8
        },
        {
          label: "较光滑",
          value: 0.6
        },
        {
          label: "光滑",
          value: 0.3
        },
        {
          label: "自定义",
          value: 0
        }
      ],
      speed: 5,
      mode: 0,
      form: {},
      form1: {},
      dialogVisible: false,
      canvasClass: '',
      full: false,
      selected: -1,
      tableData: [],
      selectedRow: null,
      editingIndex: null, // null 表示没有行在编辑
      originalName: '',
      pointData: [],
      lineData: [],
      rectData: [],
      // Canvas state
      canvas: null,
      ctx: null,
      isDrawing: false,    // Actively drawing a new shape
      isDragging: false,   // Dragging an existing shape
      isResizing: false,   // Resizing an existing shape
      dragStartX: 0,       // Mouse down X relative to canvas
      dragStartY: 0,       // Mouse down Y relative to canvas
      offsetX: 0,          // Offset between mouse down and shape origin/handle
      offsetY: 0,
      resizeHandle: null,  // Which handle is being dragged ('top-left', 'bottom-right', 'start', 'end', etc.)
      rules: {
        alarmTemp: [
          {required: true, message: '请输入报警温度', trigger: 'blur'},
        ],
        alarmFilterTime: [
          {required: true, message: '请输入报警过滤时间', trigger: 'blur'},
        ],
        alertTemp: [
          {required: true, message: '请输入预警温度', trigger: 'blur'},
        ],
        alertFilterTime: [
          {required: true, message: '请输入预警过滤时间', trigger: 'blur'},
        ],
        threshold: [
          {required: true, message: '请输入容差温度', trigger: 'blur'},
        ],
        ruleType: [
          {required: true, message: '请选择报警规则', trigger: 'change'},
        ]
      },
      tooltip: {

      },
      tooltipVisible: false,
      width: 384,
      height: 288,
      presets: Array.from({ length: 255 }, (_, i) => ({
        id: i + 1,
        name: `预置点 ${i + 1}`,
        status: false, // false: inactive/unset, true: active/set
      })),
    };
  },
  computed: {
    canvasWidth() {
      return this.canvas ? this.canvas.width : 0;
    },
    canvasHeight() {
      return this.canvas ? this.canvas.height : 0;
    }
  },
  mounted() {
    getCapabilities().then(res => {
      if (res.code === 0 && res.data) {
        this.capabilities = res.data;
      }
    });
    getMeasureMode().then(res => {
      if (res.code === 0) {
        this.mode = res.data.mode;
      } else {
        this.$message.error("获取测温模式失败");
      }
    });
    const types = ['point', 'line', 'rect'];

    for (let i = 1; i <= 60; i++) {
      const item = {
        validFlag: 0,
        id: i,
        name: `ID: ${i}`,
        type: types[(i - 1) % 3], // 使用取模运算实现循环
        emissivity: 0,
        emissivityValue: 0.96,
        distance: 3,
        reflectTemp: 20,
        coordX: null,
        coordY: null,
        startCoordX: null,
        startCoordY: null,
        endCoordX: null,
        endCoordY: null,
        rectWide: null,
        rectHigh: null,
      };
      this.tableData.push(item);
    }

    this.canvas = this.$refs.canvas;
    this.ctx = this.canvas.getContext('2d');
    this.clearCanvas(); // Initial clear
    getQueryPreset().then(res =>{
      if (res.code === 0 && res.data && res.data.presets){
        res.data.presets.forEach(apiPreset => {
          const localPreset = this.presets.find(p => p.id === apiPreset.id);
          if (localPreset) {
            localPreset.name = apiPreset.name;
            localPreset.status = true; // Mark as active
          }
        });
      }
    })
    getvideoparam().then(res => {
      this.width = res.data.width;
      this.height = res.data.height;
      getMeasurePoint().then(res => {
        res.data.points.forEach(item => {
          let index = this.tableData.findIndex(row => row.id === item.id)
          if (index !== -1) {
            this.tableData[index] = {
              ...item,
              coordY: item.coordY*345/this.height,
              coordX: item.coordX*423/this.width,
              emissivityValue: item.emissivity100 / 100,
              emissivity: this.radTable.find(r => r.value === item.emissivity100 / 100)?.value || 0,
              distance: item.distance100 / 100,
              reflectTemp: item.reflectTemp100 / 100,
              type: SHAPE_POINT,
            }
            this.$set(this.tableData, index, this.tableData[index])
          }
        });
      })
      getMeasureLine().then(res => {
        res.data.lines.forEach(item => {
          let index = this.tableData.findIndex(row => row.id === item.id)
          if (index !== -1) {
            this.tableData[index] = {
              ...item,
              endCoordY: item.endCoordY*345/this.height,
              endCoordX: item.endCoordX*423/this.width,
              startCoordY: item.startCoordY*345/this.height,
              startCoordX: item.startCoordX*423/this.width,
              emissivityValue: item.emissivity100 / 100,
              emissivity: this.radTable.find(r => r.value === item.emissivity100 / 100)?.value || 0,
              distance: item.distance100 / 100,
              reflectTemp: item.reflectTemp100 / 100,
              type: SHAPE_LINE,
            }

            this.$set(this.tableData, index, this.tableData[index])
          }
        });
      })
      getMeasurerect().then(res => {
        res.data.rects.forEach(item => {
          let index = this.tableData.findIndex(row => row.id === item.id)
          if (index !== -1) {
            this.tableData[index] = {
              ...item,
              coordY: item.coordY*345/this.height,
              coordX: item.coordX*423/this.width,
              rectWide: item.rectWide*423/this.width,
              rectHigh: item.rectHigh*345/this.height,
              emissivityValue: item.emissivity100 / 100,
              emissivity: this.radTable.find(r => r.value === item.emissivity100 / 100)?.value || 0,
              distance: item.distance100 / 100,
              reflectTemp: item.reflectTemp100 / 100,
              type: SHAPE_RECT,
            }
            this.$set(this.tableData, index, this.tableData[index])
          }
        });
      })
    })
    getMeasureParam().then(res => {
      this.form = {
        ...res.data,
        emissivityValue: 0,
        emissivity: 0,
        transmission: 0,
        ambientTempManu: 0,
        distance: 0,
        humidity: 0,
        reflectTemp: 0,
      };
      this.form.emissivityValue = this.form.emissivity100 / 100;
      this.form.emissivity = this.radTable.find(r => r.value === this.form.emissivity100 / 100)?.value || 0;
      this.form.distance = this.form.distance100 / 100;
      this.form.humidity = this.form.humidity100 / 100;
      this.form.reflectTemp = this.form.reflectTemp100 / 100;
      this.form.transmission = this.form.transmission100 / 100;
      this.form.ambientTempManu = this.form.ambientTempManu100 / 100;
      this.tableData.forEach(item => {
        item.emissivityValue = this.form.emissivityValue;
        item.distance = this.form.distance;
        item.reflectTemp = this.form.reflectTemp;
      });
    })

  },
  methods: {

    changeMode() {
      postMeasureMode({ mode: this.mode }).then(res => {
        if (res.code === 0) {
          // this.$message.success("模式切换成功");
        } else {
          this.$message.error("模式切换失败: " + res.msg);
          // 如果切换失败，重新从服务器获取正确的模式以同步UI
          // getMeasureMode().then(fetchRes => {
          //   if (fetchRes.code === 0) this.mode = fetchRes.data.mode;
          // });
        }
      }).catch(() => {
        this.$message.error("模式切换请求失败");
        // 同样，请求失败时也要恢复UI
        // getMeasureMode().then(fetchRes => {
        //   if (fetchRes.code === 0) this.mode = fetchRes.data.mode;
        // });
      });
    },

    handleClick(item, index) {
      if (!item.status) return;

      if (this.selected !== index) {
        if (this.editingIndex !== null) {
          this.finishEdit(this.presets[this.editingIndex]);
        }
        this.selected = index;
      }

      const form = {
        id: item.id,
        cmd: 'Call',
        name: item.name.trim()
      };

      postPreset(form).then(res => {
        if (res.code !== 0) {
          this.$message.error('调用预置点失败');
        }
      })
    },
    startEdit(index, item) {
      this.originalName = item.name;
      this.editingIndex = index;
      this.$nextTick(() => {
        if (this.$refs.editInput) {
          this.$refs.editInput.focus();
        }
      });
    },
    finishEdit(item) {
      if (this.editingIndex === null || !item || item.name.trim() === this.originalName) {
        this.editingIndex = null;
        return;
      }

      const form = {
        id: item.id,
        cmd: 'Set',
        name: item.name.trim()
      };

      postPreset(form).then(res => {
        if (res.code !== 0) {
          this.$message.error('更新失败，已恢复原名称');
          // Revert name on failure
          const presetToRevert = this.presets.find(p => p.id === item.id);
          if (presetToRevert) {
            presetToRevert.name = this.originalName;
          }
        }
      }).catch(() => {
        this.$message.error('更新失败，已恢复原名称');
        const presetToRevert = this.presets.find(p => p.id === item.id);
        if (presetToRevert) {
          presetToRevert.name = this.originalName;
        }
      }).finally(() => {
        this.editingIndex = null;
        this.originalName = '';
      });
    },
    setOrUpdatePreset(item) {
      // 检查当前是否处于对此项的编辑模式
      const currentIndex = this.presets.findIndex(p => p.id === item.id);
      if (this.editingIndex === currentIndex) {
        // 如果是，则调用 finishEdit 来处理名称保存逻辑
        this.finishEdit(item);
      }

      const isUpdating = item.status; // 检查是新增还是更新
      const form = {
        id: item.id,
        cmd: 'Set',
        name: item.name.trim(), // v-model 保证了 item.name 是最新的
      };

      postPreset(form).then(res => {
        if (res.code === 0) {
          item.status = true; // 激活预置点
          this.$message({
            message: isUpdating ? '更新预置点成功' : '设置预置点成功',
            type: 'success'
          });
        } else {
          this.$message.error(isUpdating ? '更新预置点失败' : '设置预置点失败');
        }
      });
    },

    // 2. 修改 removePreset 方法
    removePreset(item, index) { // 接收索引 index
      if (!item) return;

      const form = {
        id: item.id,
        cmd: 'Clear',
        name: item.name,
      }
      postPreset(form).then(res => {
        if (res.code === 0) {
          // 重置为未激活状态
          item.name = `预置点 ${item.id}`;
          item.status = false;

          // 如果删除的是当前选中的项，则取消选中
          if (this.selected === index) {
            this.selected = -1;
          }

          // 【BUG修复】如果删除的是正在编辑的项，则退出编辑模式
          if (this.editingIndex === index) {
            this.editingIndex = null;
            this.originalName = ''; // 清理原始名称
          }

          this.$message({
            message: '删除预置点成功',
            type: 'success'
          });
        } else {
          this.$message.error('删除预置点失败');
        }
      })
    },

    settingClose() {
      this.form1 = {}
    },
    save() {
      if (this.mode == 0) {
        let formData = {
          emissivity100: this.form.emissivityValue * 100,
          distance100: this.form.distance * 100,
          humidity100: this.form.humidity * 100,
          reflectTemp100: this.form.reflectTemp * 100,
          transmission100: this.form.transmission * 100,
          ambientTempManu100: this.form.ambientTempManu * 100,
        }
        postMeasureParam(formData).then(res => {
          if (res.code === 0) {
            this.$message.success("保存成功");
          } else {
            this.$message.error(res.msg);
          }
        });
      } else {
        measureClear().then(res => {
          if (res.code === 0) {
            let pointData = this.tableData.filter(item => item.type === SHAPE_POINT);
            let lineData = this.tableData.filter(item => item.type === SHAPE_LINE);
            let rectData = this.tableData.filter(item => item.type === SHAPE_RECT);
            pointData = pointData.map(item => ({
              ...item,
              coordX: Math.round(item.coordX * this.width / 423),
              coordY: Math.round(item.coordY * this.height / 345),
              emissivity100: item.emissivityValue * 100,
              distance100: item.distance * 100,
              reflectTemp100: item.reflectTemp * 100,
            }));
            lineData = lineData.map(item => ({
              ...item,
              endCoordY: Math.round(item.endCoordY * this.height / 345),
              endCoordX: Math.round(item.endCoordX * this.width / 423),
              startCoordY: Math.round(item.startCoordY * this.height / 345),
              startCoordX: Math.round(item.startCoordX * this.width / 423),
              emissivity100: item.emissivityValue * 100,
              distance100: item.distance * 100,
              reflectTemp100: item.reflectTemp * 100,
            }));
            rectData = rectData.map(item => ({
              ...item,
              coordX: Math.round(item.coordX * this.width / 423),
              coordY: Math.round(item.coordY * this.height / 345),
              rectWide: Math.round(item.rectWide * this.width / 423),
              rectHigh: Math.round(item.rectHigh * this.height / 345),
              emissivity100: item.emissivityValue * 100,
              distance100: item.distance * 100,
              reflectTemp100: item.reflectTemp * 100,
            }));
            postMeasurePoint({
              num: pointData.length,
              points: pointData
            }).then(res => {
              if (res.code === 0) {
                this.$message.success("保存成功");
                postMeasureLine({
                  num: lineData.length,
                  lines: lineData
                }).then(res => {
                  if (res.code === 0) {
                    postMeasureRect({
                      num: rectData.length,
                      rects: rectData
                    })
                  }
                })

              } else {
                this.$message.error(res.msg);
              }
            });



          } else {
            this.$message.error(res.msg);
          }
        });


      }

    },
    handleFloatInput() {
      let value = String(this.form.distance);
      value = value.replace(/[^\d.]/g, '');
      value = value.replace(/(\.\d*)\./g, '$1');
      if (value.indexOf('.') === 0) {
        value = '0' + value;
      }

      this.form.distance = value;
    },
    handleemissivityValue(event) {
      const newValue = event.target.value;
      if (newValue < 0.01 || newValue > 1) {
        this.$message.error("发射率值必须在0.01到1之间");
        this.form.emissivityValue = 0.96;
        return;
      }
    },
    handleemissivityValue2(row) {
      const newValue = row.emissivityValue;
      if (newValue < 0.01 || newValue > 1) {
        this.$message.error("发射率值必须在0.01到1之间");
        row.emissivityValue = 0.96;
        return;
      }
    },
    handleemissivity() {
      if (this.form.emissivity != 0) {
        this.form.emissivityValue = this.form.emissivity;
      }
    },
    handleemissivity2(row) {
      if (row.emissivity != 0) {
        row.emissivityValue = row.emissivity;
      }
    },
    startMove(direction) {
      direct({
        cmd: direction,
        speed: this.speed
      })
    },

    stopMove() {
      controlstop()
    },
    startFocus(cmd) {
      controlfocus({cmd})

    },
    startZoom(cmd){
      zoom({cmd})
    },

    hoverRule(row) {
      // this.tooltipVisible = true;
      // getThermalAlarmConfig({
      //   id: row.id,
      //   type: row.type
      // }).then(res => {
      //   if (res.code === 0) {
      //     this.tooltip = res.data;
      //     this.tooltipVisible = true;
      //   }
      // })
    },
    handleSettingClick(event, row) {
      const loadingInstance = this.$loading({
        lock: true,
        text: '正在加载报警规则...',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
      this.selectedRow = row;
      getThermalAlarmConfig({
        id: row.id,
        type: row.type
      }).then(res => {
        if (res.code === 0) {
          this.form1 = res.data;
          this.form1.id = row.id;
          this.form1.type = row.type;
          this.dialogVisible = true;
        } else {
          this.$message.error(res.msg);
        }
      }).catch(err => {
        this.$message.error("请求报警规则失败");
        console.error(err);
      }).finally(() => {
        loadingInstance.close();
      });
    },

    handleDialogSave() {
      if (this.form1.ruleType === '' || this.form1.ruleType === null
      || this.form1.alarmTemp === null || this.form1.alarmTemp === ''
      || this.form1.alarmFilterTime === null || this.form1.alarmFilterTime === ''
      || this.form1.alertTemp === null || this.form1.alertTemp === ''
      || this.form1.alertFilterTime === null || this.form1.alertFilterTime === '') {
        this.$message.info("请输入完整参数设置");
        return;
      }
      postThermalAlarmConfig(this.form1).then(res => {
        if (res.code === 0) {
          this.$message.success("保存成功");
        } else {
          this.$message.error(res.msg);
        }
      })
      this.dialogVisible = false;
    },
    // --- Table Methods ---
    handleCurrentRowChange(currentRow) {
      // If the same row is clicked again, currentRow might be null if deselected by clicking outside
      // Or it might be the same object if clicked again. Handle both cases.
      if (currentRow) {
        this.selectedRow = currentRow;
        console.log("Selected Row:", this.selectedRow);
        this.resetInteractionState();
        this.redrawCanvas();
      } else {
        // Row deselected
        this.selectedRow = null;
        this.resetInteractionState();
        this.clearCanvas();
      }
    },

    handleTypeChange(event, row) {
      const newType = event.target.value || null; // Get value from event target

      console.log(`Type change for row ${row.id}: ${row.type} -> ${newType}`);

      // IMPORTANT: Directly modify the row object in tableData
      const rowIndex = this.tableData.findIndex(item => item.id === row.id);
      if (rowIndex !== -1) {
        const targetRow = this.tableData[rowIndex];

        // Only update if the type actually changed
        if (targetRow.type !== newType) {
          // Update the type
          targetRow.type = newType;

          // Reset coordinate data for this row
          this.clearShapeData(targetRow);

          // If the changed row is the currently selected row, clear the canvas
          if (this.selectedRow && this.selectedRow.id === targetRow.id) {
            this.resetInteractionState();
            this.redrawCanvas(); // Redraw (will show message to draw)
          }

          // Force reactivity if needed (usually not required for direct property changes)
          // this.$set(this.tableData, rowIndex, targetRow);
          // console.log("Updated tableData:", this.tableData);
        }
      }
    },

    clearShapeData(row) {
      if (!row) return;
      row.coordX = null;
      row.coordY = null;
      row.startCoordX = null;
      row.startCoordY = null;
      row.endCoordX = null;
      row.endCoordY = null;
      row.rectWide = null;
      row.rectHigh = null;
      console.log(`Cleared shape data for row ${row.id}`);
    },

    hasShapeData(row) {
      if (!row || !row.type) return false;
      switch (row.type) {
        case SHAPE_POINT: return row.coordX !== null && row.coordY !== null;
        case SHAPE_LINE: return row.startCoordX !== null && row.startCoordY !== null && row.endCoordX !== null && row.endCoordY !== null;
        case SHAPE_RECT: return row.coordX !== null && row.coordY !== null && row.rectWide !== null && row.rectHigh !== null;
        default: return false;
      }
    },

    getShapeName(type) {
      switch (type) {
        case SHAPE_POINT: return '点';
        case SHAPE_LINE: return '线';
        case SHAPE_RECT: return '框';
        default: return '形状';
      }
    },

    // --- Canvas Drawing ---
    clearCanvas() {
      if (!this.ctx || !this.canvas) return;
      this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
    },

    redrawCanvas() {
      if (!this.ctx || !this.canvas) return;
      this.clearCanvas();

      if (!this.selectedRow || !this.selectedRow.type || !this.hasShapeData(this.selectedRow)) {
        // No selected row, no type, or no data to draw - canvas remains clear (messages handled by divs)
        this.setCursor('default');
        return;
      }

      // Set drawing styles
      this.ctx.strokeStyle = 'blue';
      this.ctx.fillStyle = 'blue';
      this.ctx.lineWidth = 2;
      this.ctx.font = '12px Arial';

      const row = this.selectedRow;

      try { // Add try-catch for safety during drawing/resizing
        switch (row.type) {
          case SHAPE_POINT:
            this.drawPoint(row.coordX, row.coordY);
            break;
          case SHAPE_LINE:
            this.drawLine(row.startCoordX, row.startCoordY, row.endCoordX, row.endCoordY);
            // --- MODIFICATION START ---
            // Original code had an if condition here. It has been removed.
            // Now, handles are always drawn for a selected line.
            this.drawHandlesLine(row.startCoordX, row.startCoordY, row.endCoordX, row.endCoordY);
            // --- MODIFICATION END ---
            break;
          case SHAPE_RECT:
            this.drawRect(row.coordX, row.coordY, row.rectWide, row.rectHigh);
            // --- MODIFICATION START ---
            // Original code had an if condition here. It has been removed.
            // Now, handles are always drawn for a selected rectangle.
            this.drawHandlesRect(row.coordX, row.coordY, row.rectWide, row.rectHigh);
            // --- MODIFICATION END ---
            break;
        }
      } catch (e) {
        console.error("Error during drawing:", e, "Row data:", row);
        // Optionally reset state or show an error
      }
    },

    drawPoint(x, y) {
      if (x === null || y === null) return;
      // Crosshair
      this.ctx.beginPath();
      this.ctx.moveTo(x - POINT_SIZE, y);
      this.ctx.lineTo(x + POINT_SIZE, y);
      this.ctx.moveTo(x, y - POINT_SIZE);
      this.ctx.lineTo(x, y + POINT_SIZE);
      // this.ctx.moveTo(x - POINT_SIZE, y);
      // this.ctx.lineTo(x - 3, y); // 留出1像素的间隙，或者你可以设置为 x - GAP_SIZE
      //
      // // 水平线段 - 右半部分
      // this.ctx.moveTo(x + 3, y); // 从间隙后开始
      // this.ctx.lineTo(x + POINT_SIZE, y);
      //
      // // 垂直线段 - 上半部分
      // this.ctx.moveTo(x, y - POINT_SIZE);
      // this.ctx.lineTo(x, y - 3); // 留出1像素的间隙
      //
      // // 垂直线段 - 下半部分
      // this.ctx.moveTo(x, y + 3); // 从间隙后开始
      // this.ctx.lineTo(x, y + POINT_SIZE);
      //
      this.ctx.strokeStyle = 'red';
      this.ctx.lineWidth = 2;
      this.ctx.stroke();
      // // Center dot (optional)
      // this.ctx.beginPath();
      // this.ctx.arc(x, y, 2, 0, Math.PI * 2);
      // this.ctx.fillStyle = 'red';
      // this.ctx.fill();
    },

    drawLine(x1, y1, x2, y2) {
      if (x1 === null || y1 === null || x2 === null || y2 === null) return;
      this.ctx.beginPath();
      this.ctx.moveTo(x1, y1);
      this.ctx.lineTo(x2, y2);
      this.ctx.strokeStyle = 'red';
      this.ctx.lineWidth = 2;
      this.ctx.stroke();
    },

    drawRect(x, y, w, h) {
      if (x === null || y === null || w === null || h === null) return;
      this.ctx.beginPath();
      this.ctx.rect(x, y, w, h);
      this.ctx.strokeStyle = '#ffff00';
      this.ctx.lineWidth = 2;
      this.ctx.stroke();
    },

    drawHandlesRect(x, y, w, h) {
      this.ctx.fillStyle = '#ffff00'; // Blue handles
      const handles = this.getRectHandles(x, y, w, h);
      Object.values(handles).forEach(pos => {
        this.ctx.fillRect(pos.x - HANDLE_SIZE / 2, pos.y - HANDLE_SIZE / 2, HANDLE_SIZE, HANDLE_SIZE);
      });
    },

    drawHandlesLine(x1, y1, x2, y2) {
      this.ctx.fillStyle = 'red'; // Blue handles
      const handles = this.getLineHandles(x1, y1, x2, y2);
      Object.values(handles).forEach(pos => {
        this.ctx.fillRect(pos.x - HANDLE_SIZE / 2, pos.y - HANDLE_SIZE / 2, HANDLE_SIZE, HANDLE_SIZE);
      });
    },


    // --- Canvas Interaction ---

    getMousePos(event) {
      const rect = this.canvas.getBoundingClientRect();
      return {
        x: event.clientX - rect.left,
        y: event.clientY - rect.top,
      };
    },

    resetInteractionState() {
      this.isDrawing = false;
      this.isDragging = false;
      this.isResizing = false;
      this.resizeHandle = null;
      this.offsetX = 0;
      this.offsetY = 0;
    },

    setCursor(style) {
      this.canvas.style.cursor = style;
    },

    handleDoubleClick() {
      console.log("f")
      // if (screenfull.isEnabled) { // 检查浏览器是否支持全屏
      //   const containerElement = document.getElementById("c");
      //   screenfull.toggle(containerElement); // 切换全屏状态
      //   setTimeout(() => {
      //
      //     this.full = !this.full;
      //   }, 1500)
      // } else {
      //   console.warn("Fullscreen API is not enabled or supported in this browser.");
      // }
    },
    handleMouseDown(event) {
      if (event.button !== 0) return; // Only left click

      if (!this.selectedRow || !this.selectedRow.type) {
        this.setCursor('not-allowed');
        return; // No row selected or no type chosen
      }

      const pos = this.getMousePos(event);
      this.dragStartX = pos.x;
      this.dragStartY = pos.y;

      const row = this.selectedRow;

      // 1. Check if shape data exists for the current type
      if (!this.hasShapeData(row)) {
        // Start drawing new shape
        this.isDrawing = true;
        // Initialize shape based on type at mouse down location
        switch (row.type) {
          case SHAPE_POINT:
            row.coordX = pos.x;
            row.coordY = pos.y;
            this.isDrawing = false; // Point is placed instantly on mousedown
            this.redrawCanvas();
            break;
          case SHAPE_LINE:
            row.startCoordX = pos.x;
            row.startCoordY = pos.y;
            row.endCoordX = pos.x; // Start and end at same point initially
            row.endCoordY = pos.y;
            break;
          case SHAPE_RECT:
            row.coordX = pos.x;
            row.coordY = pos.y;
            row.rectWide = 0; // Start with zero size
            row.rectHigh = 0;
            break;
        }
        if (row.type !== SHAPE_POINT) this.redrawCanvas(); // Redraw initial point/rect
        this.setCursor('crosshair');

      } else {
        // Shape exists, check for drag or resize
        this.resizeHandle = this.getHandleAtPos(pos.x, pos.y, row);

        if (this.resizeHandle) {
          // Start resizing
          this.isResizing = true;
          this.offsetX = 0; // Offset calculation might differ for resizing, handle in mousemove
          this.offsetY = 0;
          this.setCursor(this.getResizeCursor(this.resizeHandle));
          this.redrawCanvas(); // Redraw to show handles
        } else if (this.isPointOnShape(pos.x, pos.y, row)) {
          // Start dragging
          this.isDragging = true;
          // Calculate offset based on shape type
          switch (row.type) {
            case SHAPE_POINT:
              this.offsetX = pos.x - row.coordX;
              this.offsetY = pos.y - row.coordY;
              break;
            case SHAPE_LINE: // Dragging line = moving both points
              this.offsetX = pos.x - row.startCoordX;
              this.offsetY = pos.y - row.startCoordY;
              // Store relative position of end point to start point
              this.offsetX2 = row.endCoordX - row.startCoordX;
              this.offsetY2 = row.endCoordY - row.startCoordY;
              break;
            case SHAPE_RECT:
              this.offsetX = pos.x - row.coordX;
              this.offsetY = pos.y - row.coordY;
              break;
          }
          this.setCursor('move');
          this.redrawCanvas(); // Redraw to show handles maybe?
        } else {
          // Clicked outside existing shape - do nothing? Or maybe deselect?
          this.resetInteractionState();
          this.setCursor('default');
        }
      }
    },

    handleMouseMove(event) {
      if (!this.selectedRow || !this.selectedRow.type) return;

      const pos = this.getMousePos(event);
      const row = this.selectedRow;

      if (this.isDrawing) {
        // Update shape being drawn
        switch (row.type) {
          case SHAPE_LINE:
            row.endCoordX = pos.x;
            row.endCoordY = pos.y;
            break;
          case SHAPE_RECT:
            row.rectWide = pos.x - this.dragStartX;
            row.rectHigh = pos.y - this.dragStartY;
            // Normalize rectangle: origin should be top-left
            if (row.rectWide < 0) {
              row.coordX = pos.x;
              row.rectWide = -row.rectWide;
            }
            if (row.rectHigh < 0) {
              row.coordY = pos.y;
              row.rectHigh = -row.rectHigh;
            }
            break;
        }
        this.redrawCanvas();

      } else if (this.isDragging) {
        // Update shape position while dragging
        let newX, newY, newStartX, newStartY, newEndX, newEndY;
        switch (row.type) {
          case SHAPE_POINT:
            newX = pos.x - this.offsetX;
            newY = pos.y - this.offsetY;
            // Clamp to canvas bounds
            row.coordX = Math.max(0, Math.min(this.canvasWidth, newX));
            row.coordY = Math.max(0, Math.min(this.canvasHeight, newY));
            break;
          case SHAPE_LINE:
            newStartX = pos.x - this.offsetX;
            newStartY = pos.y - this.offsetY;
            newEndX = newStartX + this.offsetX2;
            newEndY = newStartY + this.offsetY2;
            // Basic bounds check (prevent entire line going off-screen easily) - more complex checks needed for perfect clamping
            if (newStartX >= 0 && newEndX >= 0 && newStartX <= this.canvasWidth && newEndX <= this.canvasWidth) {
              row.startCoordX = newStartX;
              row.endCoordX = newEndX;
            }
            if (newStartY >= 0 && newEndY >= 0 && newStartY <= this.canvasHeight && newEndY <= this.canvasHeight) {
              row.startCoordY = newStartY;
              row.endCoordY = newEndY;
            }
            break;
          case SHAPE_RECT:
            newX = pos.x - this.offsetX;
            newY = pos.y - this.offsetY;
            // Clamp to canvas bounds
            row.coordX = Math.max(0, Math.min(this.canvasWidth - row.rectWide, newX));
            row.coordY = Math.max(0, Math.min(this.canvasHeight - row.rectHigh, newY));
            break;
        }
        this.redrawCanvas();

      } else if (this.isResizing) {
        // Update shape dimensions/endpoints while resizing
        this.performResize(pos.x, pos.y, row);
        this.redrawCanvas();
      } else {
        // Not interacting, just moving mouse: update cursor if over shape/handles
        const handle = this.getHandleAtPos(pos.x, pos.y, row);
        if (handle) {
          this.setCursor(this.getResizeCursor(handle));
        } else if (this.hasShapeData(row) && this.isPointOnShape(pos.x, pos.y, row)) {
          this.setCursor('move');
        } else {
          this.setCursor('default'); // Or 'crosshair' if drawing is possible
        }
      }
    },

    handleMouseUp(event) {
      if (event.button !== 0) return;
      if (!this.selectedRow) return;

      if (this.isDrawing) {
        // Finalize drawing
        if (this.selectedRow.type === SHAPE_RECT) {
          // Normalize rect again after final mouse up
          if (this.selectedRow.rectWide < 0) {
            this.selectedRow.coordX += this.selectedRow.rectWide; // Adjust origin
            this.selectedRow.rectWide = -this.selectedRow.rectWide;
          }
          if (this.selectedRow.rectHigh < 0) {
            this.selectedRow.coordY += this.selectedRow.rectHigh; // Adjust origin
            this.selectedRow.rectHigh = -this.selectedRow.rectHigh;
          }
          // Prevent zero-size rects? Optional.
          if (this.selectedRow.rectWide < 5) this.selectedRow.rectWide = 5;
          if (this.selectedRow.rectHigh < 5) this.selectedRow.rectHigh = 5;
        }
        else if (this.selectedRow.type === SHAPE_LINE) {
          // Prevent zero-length lines? Optional.
          const dx = this.selectedRow.endCoordX - this.selectedRow.startCoordX;
          const dy = this.selectedRow.endCoordY - this.selectedRow.startCoordY;
          if (dx*dx + dy*dy < 10) { // If length is less than ~3 pixels
            this.selectedRow.endCoordX += 5; // Give it a small default length
          }
        }
        this.isDrawing = false;
        this.setCursor('default');
        this.redrawCanvas(); // Redraw final shape without interaction indicators
        console.log("Finished Drawing:", this.selectedRow);


      } else if (this.isDragging || this.isResizing) {
        this.isDragging = false;
        this.isResizing = false;
        this.resizeHandle = null;
        this.setCursor('default');
        this.redrawCanvas(); // Redraw final shape without interaction indicators
        console.log("Finished Interaction:", this.selectedRow);
      }
      this.resetInteractionState(); // Ensure clean state
    },

    handleMouseLeave(event) {
      // If mouse leaves canvas while drawing/dragging, cancel the operation
      if (this.isDrawing || this.isDragging || this.isResizing) {
        console.log("Mouse left canvas during interaction, resetting.");
        // Option 1: Reset to state before interaction (more complex)
        // Option 2: Finalize state as is (simpler, might leave weird shapes)
        // Let's go with finalizing: call mouseup logic
        this.handleMouseUp({ button: 0 }); // Simulate left mouse button up
      }
      this.setCursor('default');
    },


    // --- Hit Detection & Resizing Logic ---

    isPointOnShape(x, y, row) {
      if (!row || !row.type || !this.hasShapeData(row)) return false;

      switch (row.type) {
        case SHAPE_POINT:
          return Math.abs(x - row.coordX) <= POINT_SIZE && Math.abs(y - row.coordY) <= POINT_SIZE;
        case SHAPE_LINE:
          // Check distance from point to line segment
          const x1 = row.startCoordX, y1 = row.startCoordY;
          const x2 = row.endCoordX, y2 = row.endCoordY;
          const lenSq = (x2 - x1) ** 2 + (y2 - y1) ** 2;
          if (lenSq === 0) return Math.sqrt((x - x1)**2 + (y - y1)**2) < LINE_DETECT_THRESHOLD; // It's a point
          let t = ((x - x1) * (x2 - x1) + (y - y1) * (y2 - y1)) / lenSq;
          t = Math.max(0, Math.min(1, t)); // Clamp t to [0, 1]
          const projX = x1 + t * (x2 - x1);
          const projY = y1 + t * (y2 - y1);
          const dist = Math.sqrt((x - projX)**2 + (y - projY)**2);
          return dist < LINE_DETECT_THRESHOLD;
        case SHAPE_RECT:
          // Check if point is inside the rectangle bounds
          return x >= row.coordX && x <= row.coordX + row.rectWide &&
            y >= row.coordY && y <= row.coordY + row.rectHigh;
      }
      return false;
    },

    getHandleAtPos(x, y, row) {
      if (!row || !row.type || !this.hasShapeData(row)) return null;

      let handles = {};
      if (row.type === SHAPE_RECT) {
        handles = this.getRectHandles(row.coordX, row.coordY, row.rectWide, row.rectHigh);
      } else if (row.type === SHAPE_LINE) {
        handles = this.getLineHandles(row.startCoordX, row.startCoordY, row.endCoordX, row.endCoordY);
      } else {
        return null; // Points don't have resize handles
      }

      const halfHandle = HANDLE_SIZE / 2;
      for (const name in handles) {
        const handlePos = handles[name];
        if (x >= handlePos.x - halfHandle && x <= handlePos.x + halfHandle &&
          y >= handlePos.y - halfHandle && y <= handlePos.y + halfHandle) {
          return name;
        }
      }
      return null;
    },

    getRectHandles(x, y, w, h) {
      // Ensure w and h are positive for handle calculation consistency
      const x2 = x + w;
      const y2 = y + h;
      return {
        'top-left': { x: x, y: y },
        'top-right': { x: x2, y: y },
        'bottom-left': { x: x, y: y2 },
        'bottom-right': { x: x2, y: y2 },
        'top': { x: x + w / 2, y: y },
        'bottom': { x: x + w / 2, y: y2 },
        'left': { x: x, y: y + h / 2 },
        'right': { x: x2, y: y + h / 2 },
      };
    },

    getLineHandles(x1, y1, x2, y2) {
      return {
        'start': { x: x1, y: y1 },
        'end': { x: x2, y: y2 },
      };
    },

    getResizeCursor(handleName) {
      switch (handleName) {
        case 'top-left': case 'bottom-right': return 'nwse-resize';
        case 'top-right': case 'bottom-left': return 'nesw-resize';
        case 'top': case 'bottom': return 'ns-resize';
        case 'left': case 'right': return 'ew-resize';
        case 'start': case 'end': return 'pointer'; // Or 'grab'/'grabbing'
        default: return 'default';
      }
    },

    performResize(mouseX, mouseY, row) {
      if (!this.resizeHandle) return;

      const minSize = 10; // Minimum width/height or line length

      switch (row.type) {
        case SHAPE_LINE:
          if (this.resizeHandle === 'start') {
            // Prevent line collapsing
            if (Math.sqrt((row.endCoordX - mouseX)**2 + (row.endCoordY - mouseY)**2) > minSize) {
              row.startCoordX = mouseX;
              row.startCoordY = mouseY;
            }
          } else if (this.resizeHandle === 'end') {
            // Prevent line collapsing
            if (Math.sqrt((mouseX - row.startCoordX)**2 + (mouseY - row.startCoordY)**2) > minSize) {
              row.endCoordX = mouseX;
              row.endCoordY = mouseY;
            }
          }
          break;
        case SHAPE_RECT:
          const originalX = row.coordX;
          const originalY = row.coordY;
          const originalW = row.rectWide;
          const originalH = row.rectHigh;
          const right = originalX + originalW;
          const bottom = originalY + originalH;

          switch (this.resizeHandle) {
            case 'top-left':
              row.coordX = Math.min(mouseX, right - minSize);
              row.coordY = Math.min(mouseY, bottom - minSize);
              row.rectWide = right - row.coordX;
              row.rectHigh = bottom - row.coordY;
              break;
            case 'top-right':
              row.coordY = Math.min(mouseY, bottom - minSize);
              row.rectWide = Math.max(mouseX - originalX, minSize);
              row.rectHigh = bottom - row.coordY;
              break;
            case 'bottom-left':
              row.coordX = Math.min(mouseX, right - minSize);
              row.rectWide = right - row.coordX;
              row.rectHigh = Math.max(mouseY - originalY, minSize);
              break;
            case 'bottom-right':
              row.rectWide = Math.max(mouseX - originalX, minSize);
              row.rectHigh = Math.max(mouseY - originalY, minSize);
              break;
            case 'top':
              row.coordY = Math.min(mouseY, bottom - minSize);
              row.rectHigh = bottom - row.coordY;
              break;
            case 'bottom':
              row.rectHigh = Math.max(mouseY - originalY, minSize);
              break;
            case 'left':
              row.coordX = Math.min(mouseX, right - minSize);
              row.rectWide = right - row.coordX;
              break;
            case 'right':
              row.rectWide = Math.max(mouseX - originalX, minSize);
              break;
          }
          // Clamp rectangle position/size to canvas bounds after resize attempt
          row.coordX = Math.max(0, row.coordX);
          row.coordY = Math.max(0, row.coordY);
          if (row.coordX + row.rectWide > this.canvasWidth) {
            row.rectWide = this.canvasWidth - row.coordX;
          }
          if (row.coordY + row.rectHigh > this.canvasHeight) {
            row.rectHigh = this.canvasHeight - row.coordY;
          }
          // Ensure minimum size after clamping
          row.rectWide = Math.max(minSize, row.rectWide);
          row.rectHigh = Math.max(minSize, row.rectHigh);
          break;
      }
    },

    handleTempOutputClick(event, row) {
      const loadingInstance = this.$loading({
        lock: true,
        text: '正在加载测温输出配置...',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.7)'
      });
      this.selectedRow = row;
      getTempOutputConfig({
        type: row.type,
        id: row.id,
      }).then(res => {
        if (res.code === 0) {
          this.tempOutputForm = { ...res.data };
          this.tempOutputForm.type = row.type;
          this.tempOutputForm.id = row.id;
          this.tempOutputDialogVisible = true;
        } else {
          this.$message.error(res.msg || '获取测温输出配置失败');
        }
      }).catch(err => {
        this.$message.error('请求测温输出配置失败');
        console.error(err);
      }).finally(() => {
        loadingInstance.close();
      });
    },

    handleTempOutputSave() {
      if (this.tempOutputForm.outputAddr < 1 || this.tempOutputForm.outputAddr > 255 || !Number.isInteger(this.tempOutputForm.outputAddr)) {
        this.$message.error('输出地址必须是1-255之间的整数');
        return;
      }

      const payload = {
        enable: this.tempOutputForm.enable,
        type: this.tempOutputForm.type,
        id: this.tempOutputForm.id,
        outputType: this.tempOutputForm.outputType,
        outputAddr: this.tempOutputForm.outputAddr,
        tempType: this.tempOutputForm.type === 'point' ? undefined : this.tempOutputForm.tempType,
        outputInterval: this.tempOutputForm.outputInterval,
        calcType: this.tempOutputForm.calcType,
      };

      postTempOutputConfig(payload).then(res => {
        if (res.code === 0) {
          this.$message.success("保存成功");
          this.tempOutputDialogVisible = false;
        } else {
          this.$message.error(res.msg || '保存失败');
        }
      });
    },

    tempOutputDialogClose() {
      this.tempOutputForm = {};
    },
  },
};
</script>

<style scoped>


.el-form-item .el-form-item {
  margin-bottom: 10px;
}
select {
  width: 202px;
}
.a1 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat 0 0;
}
.a2 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -30px 0px;
}
.a3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -60px 0px;
}
.a4 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat 0 -30px;
}
.a5 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -30px -30px;
}
.a6 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -60px -30px;
}
.a7 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat 0px -60px;
}
.a8 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -30px -60px;
}
.a9 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  display: inline-block;
  width: 30px;
  height: 30px;
  margin: 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat -60px -60px;
}
.a {
  cursor: pointer;
}
.a:hover {
  background-image: url("~@/assets/images/ptz-red.png");
}

.b1 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -90px 0;
}
.b2 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -126px 0;
}
.b3 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -90px -30px;
}
.b4 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -126px -30px;
}
.b5 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -90px -62px;
}
.b6 {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  text-align: right;
  cursor: pointer;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: left;
  width: 36px;
  height: 30px;
  margin: 1px 0 1px 1px;
  background: url("~@/assets/images/ptz.png") no-repeat;
  background-position: -127px -62px;
}

.e {
  font-family: Arial, Helvetica, sans-serif;
  font-size: 12px;
  visibility: visible;
  line-height: 20px;
  padding: 0;
  -webkit-text-size-adjust: none;
  float: right;
  height: 20px;
  margin: 1px 0 1px 1px;
  cursor: pointer;
  background-image: url("~@/assets/images/ptz.png");
  width: 20px;
  background-position: -35px -152px;
}

.t input, .t select {
  width: 100px !important;
}
</style>
